#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkDataSetMapper.h>
#include <vtkIdList.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPoints.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkUnstructuredGrid.h>
#include <vtkXMLUnstructuredGridWriter.h>

int main(int, char*[])
{
  vtkNew<vtkNamedColors> colors;

  // create polyhedron (cube)

  // Create points in an arbitrary order
  vtkNew<vtkPoints> points;
  points->InsertNextPoint(-5.0, -5.0, -10.0);
  points->InsertNextPoint(-5.0, -5.0, 10.0);
  points->InsertNextPoint(-5.0, 5.0, -10.0);
  points->InsertNextPoint(-5.0, 5.0, 10.0);
  points->InsertNextPoint(5.0, -5.0, -10.0);
  points->InsertNextPoint(5.0, -5.0, 10.0);
  points->InsertNextPoint(5.0, 5.0, -10.0);
  points->InsertNextPoint(5.0, 5.0, 10.0);

  // The ID of the points that compose the polyhedron cell
  vtkIdType pointIds[8] = {0, 1, 2, 3, 4, 5, 6, 7};

  // The ID of the points that compose each individual faces
  vtkNew<vtkCellArray> faces;
  vtkIdType face0[4] = { 0, 2, 6, 4 };
  vtkIdType face1[4] = { 1, 3, 7, 5 };
  vtkIdType face2[4] = { 0, 1, 3, 2 };
  vtkIdType face3[4] = { 4, 5, 7, 6 };
  vtkIdType face4[4] = { 0, 1, 5, 4 };
  vtkIdType face5[4] = { 2, 3, 7, 6 };

  // Insert each face
  faces->InsertNextCell(4, face0);
  faces->InsertNextCell(4, face1);
  faces->InsertNextCell(4, face2);
  faces->InsertNextCell(4, face3);
  faces->InsertNextCell(4, face4);
  faces->InsertNextCell(4, face5);

  // Add the IDs of the faces for the polyhedron cell
  vtkNew<vtkCellArray> faceLocations;
  vtkIdType faceIds[6] = { 0, 1, 2, 3, 4, 5 };
  faceLocations->InsertNextCell(6, faceIds);

  // Insert the polyhedron cell   
  vtkNew<vtkCellArray> cells;
  cells->InsertNextCell(8, pointIds);

  // Insert the type of the cell
  vtkNew<vtkUnsignedCharArray> cellTypes;
  cellTypes->InsertNextValue(VTK_POLYHEDRON);

  // Create hexahedron 

  // Create points in hexahedron order
  points->InsertNextPoint(-5.0, -5.0, 15.0);
  points->InsertNextPoint(5.0, -5.0, 15.0);
  points->InsertNextPoint(5.0, 5.0, 15.0);
  points->InsertNextPoint(-5.0, 5.0, 15.0);
  points->InsertNextPoint(-5.0, -5.0, 35.0);
  points->InsertNextPoint(5.0, -5.0, 35.0);
  points->InsertNextPoint(5.0, 5.0, 35.0);
  points->InsertNextPoint(-5.0, 5.0, 35.0);

  // The ID of the points of the hexahedron
  vtkIdType pointIdsh[8] = { 8, 9, 10, 11, 12, 13, 14, 15 };

  // Add the ID of the "faces" for the hexahedon, its empty because hexahedron does not need faces
  // But we still need faceLocations to have the same size as the number of cells
  faceLocations->InsertNextCell(0);

  // Insert the hexahedron
  cells->InsertNextCell(8, pointIdsh);

  // Insert the cell type
  cellTypes->InsertNextValue(VTK_HEXAHEDRON);

  // Set points and polyhedral cells
  vtkNew<vtkUnstructuredGrid> ugrid0;
  ugrid0->SetPoints(points);
  ugrid0->SetPolyhedralCells(cellTypes, cells, faceLocations, faces);

  // Create a mapper and actor
  vtkNew<vtkDataSetMapper> mapper;
  mapper->SetInputData(ugrid0);

  vtkNew<vtkActor> actor;
  actor->SetMapper(mapper);
  actor->GetProperty()->SetColor(colors->GetColor3d("Silver").GetData());

  // Visualize.
  vtkNew<vtkRenderer> renderer;
  vtkNew<vtkRenderWindow> renderWindow;
  renderWindow->SetWindowName("Polyhedron");
  renderWindow->AddRenderer(renderer);
  vtkNew<vtkRenderWindowInteractor> renderWindowInteractor;
  renderWindowInteractor->SetRenderWindow(renderWindow);

  renderer->AddActor(actor);
  renderer->SetBackground(colors->GetColor3d("Salmon").GetData());
  renderer->ResetCamera();
  renderer->GetActiveCamera()->Azimuth(30);
  renderer->GetActiveCamera()->Elevation(30);
  renderWindow->Render();
  renderWindowInteractor->Start();

  return EXIT_SUCCESS;
}
